"为什么 netstat 里有几万个 TIME_WAIT?""该用长连接还是短连接?"——这是后端与运维面试的高频题,也是线上真实故障的常见源头。
本模块按四个模块展开:长连接与短连接的原理、各自的应用场景、TIME_WAIT 与 TCP 连接的关系,以及系统层面的优化方案。
netstat、sysctl 等命令与 HTTP 协议基础tcp_tw_reuse、tcp_max_tw_buckets 等 TIME_WAIT 优化参数,厘清 tcp_fin_timeout 的真实含义上图为长短连接的行为对比:短连接每次传输都要"建连→传数据→断连",传第二份数据时重新建连;长连接建立后保持通道,多次传输(传数据 1、2、3)复用同一条连接,无需反复建连。
以 Nginx 为例:
keepalive_timeout 0; # 关闭长连接,仅支持短连接
keepalive_timeout 120s; # 支持 2 分钟的长连接通过浏览器开发者工具可验证:Request Headers 与 Response Headers 中 Connection: keep-alive 表示双向建立了长连接(Keep-Alive)。
| 协议版本 | 连接能力 | 说明 |
|---|---|---|
| HTTP/1.0 | 不支持长连接 | 每次请求都要新建 TCP 连接 |
| HTTP/1.1 | 支持长连接 | 可复用连接,但请求响应串行 |
| HTTP/2.0 | 长连接 + 多路复用 | 同一条连接上并发传输多个请求响应 |
HTTP/1.1 下请求 index.html、aa.css、bb.js 必须串行:一个请求完成后才能发起下一个;HTTP/2.0 可以在同一条 TCP 连接上同时发起多个请求、并行接收响应,这就是多路复用(Multiplexing)。
| 维度 | 短连接 | 长连接 |
|---|---|---|
| TCP 建连开销 | 每次传输都建连,开销大 | 只建一次,开销小 |
| 探活开销 | 无 | 需持续探活保持通道,有资源开销 |
| 同并发下服务端压力 | 连接周期短,压力略小 | 连接常驻,整体开销更大 |
| 服务端主动推送 | 做不到 | 支持(聊天室等场景) |
选择逻辑:大部分 Web 服务与 API 用短连接;长连接集中用于三类场景——数据库连接池(固定数量的连接通道)、聊天室(双向通信)、消息推送(服务端主动下发)。
主动关闭方发出 FIN → 被动方回 ACK → 被动方再发 FIN+ACK → 主动方回 ACK 后进入 TIME_WAIT 状态。
上图为 TCP 四次挥手产生 TIME_WAIT 的过程:主动关闭方先发 FIN,被动方回 ACK;被动方发 FIN+ACK,主动方回 ACK 后进入 TIME_WAIT 状态。四次挥手理论上已结束,但 TCP 协议需要保证最后一次 ACK 的稳定性——若 ACK 丢失需重发,同时确保旧连接的数据包不会串扰新连接,因此保留 TIME_WAIT 状态。
上图为连接方式的选择路径:常规 Web 服务与 API 多用短连接;需要复用通道、支持服务端推送的场景(数据库连接池、聊天室、消息推送)采用长连接(Keep-Alive)。选择核心是在"TCP 建连开销"与"长连接探活开销"之间权衡。
sysctl -w net.ipv4.tcp_max_tw_buckets=200000在系统资源允许的前提下调高 tcp_max_tw_buckets,增大缓冲容量,避免操作系统过早强制回收 time-wait socket(超过该值时内核会清除最旧记录并打印 "time wait bucket table overflow" 告警)。
# 开启 TIME_WAIT 复用:主动关闭方(典型为客户端)可安全复用 TIME_WAIT 连接
# 依赖 tcp_timestamps=1(默认开启)
sysctl -w net.ipv4.tcp_tw_reuse=1
# 扩大本地可用端口范围,缓解源端口耗尽
sysctl -w net.ipv4.ip_local_port_range="1024 65535"两个常见误区需要澄清:
tcp_fin_timeout 并不控制 TIME_WAIT 时长:它控制的是 FIN_WAIT_2 状态的超时(对端迟迟不发 FIN 时本端的等待上限);因此 TIME_WAIT 过多的正解是:tcp_tw_reuse 复用连接 + 服务端配置 keepalive、客户端使用连接池从源头减少连接数;tcp_max_tw_buckets 只作容量兜底。
/etc/sysctl.conf 持久化,并 sysctl -p 生效:# 写入配置文件持久化
echo "net.ipv4.tcp_tw_reuse = 1" >> /etc/sysctl.conf
echo "net.ipv4.ip_local_port_range = 1024 65535" >> /etc/sysctl.conf
echo "net.ipv4.tcp_max_tw_buckets = 200000" >> /etc/sysctl.conf
sysctl -p # 立即生效tcp_fin_timeout 当 TIME_WAIT 时长:它实际控制 FIN_WAIT_2 状态的超时;TIME_WAIT 固定 60 秒(2MSL)不可调,优化应使用 tcp_tw_reuse。sysctl -w 仅当前会话有效,需写入 /etc/sysctl.conf 并 sysctl -p 生效。netstat、ss、sysctl、Nginx keepalive_timeout 配置的官方文档。tcp_tw_reuse 复用连接、ip_local_port_range 扩大端口、tcp_max_tw_buckets 容量兜底,配合 keepalive 与连接池从源头减少连接数。